/** Featherweight Scala concrete syntax
rep(x: production) = x | x rep(x)
seprep(x: production, s: production) = x | x s seprep(x,s)
// production@? denotes a bindable production
// production@name marks production as a binder (and introduces 'name' at the meta-level to identify this binder)
// <name> activates the binder: every time a corresponding bindable production is encountered, 
//        it's replaced by a link to the binder
// </name> binder is removed from the stack

path = ident@? opt('.' seprep(ident, '.'))
term = 'new' type | 'let' ident@x ':' type '=' term 'in' <x>term</x> | 'unit'
       | path '(' seprep(term, ',') ')' 
       | path 
type = sig | 'Unit' | path '.' 'type' | path 
sig = '(' seprep(type, ',') ')' '{' ident@self '|' <self>rep(member)</self> '}'
member = 'val' ident ':' type opt('=' term) 
       | 'def' ident '(' seprep(ident@x_i ':' type, ',') ')' opt('=' term[x_i]) 
       | 'type' ident opt('=' type) 
       | 'trait' ident sig
**/

case class New(tp: Type) extends Term
case class Let(tp: Type, value: Term, scope: UnderBinder[Term, Term]) extends Term
case object unit extends Term
case class MethodCall(target: Term, actuals: List[Term]) extends Term
case class FieldSel(path: Term) extends Term

case class TypeSig(parents: List[Type], members: UnderBinder[Term, List[Member]]) extends Type
case object Unit extends Type
case class SingletonType(path: Term) extends Type
case class TypeSel(path: Term) extends Type

case class Field(name: String, tp: Type, value: Option[Term])
case class Method(name: String, formals: List[Pair[String, Type]], tp: Type, value: Option[Term])
case class Type(name: String, value: Option[Type])
case class Trait(name: String, value: TypeSig)
